@file:Suppress("unused")

package com.sscl.easyble

import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothProfile
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.Size
import com.sscl.easyble.enums.LogLevel
import com.sscl.easyble.extensions.hasBluetoothConnectPermission
import com.sscl.easyble.interfaces.OnBluetoothStateChangedListener
import com.sscl.easyble.interfaces.OnDeviceBondStateChangedListener
import com.sscl.easyble.receiver.DeviceBoundBroadcastReceiver
import com.sscl.easyble.variable.GlobalConnectVariable
import com.sscl.easyble.variable.GlobalVariable
import java.util.Locale
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.ThreadFactory

object BleManager {

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 私有属性
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /* * * * * * * * * * * * * * * * * * * 常量私有属性 * * * * * * * * * * * * * * * * * * */

    private const val TAG = "BleManager"

    /**
     * 线程工厂
     */
    private val threadFactory = ThreadFactory { r -> Thread(r) }

    private val deviceBoundStateReceiver = DeviceBoundBroadcastReceiver()

    private val scannerList = arrayListOf<BleScanner>()

    /* * * * * * * * * * * * * * * * * * * 可空私有属性 * * * * * * * * * * * * * * * * * * */

    /**
     * 蓝牙管理器
     */
    private var bluetoothManager: BluetoothManager? = null

    /**
     * 蓝牙扫描器单例
     */
    private var bleScannerInstance: BleScanner? = null

    /**
     * 蓝牙连接器单例
     */
    private var bleConnectorInstance: BleConnector? = null

    /**
     * 蓝牙广播器单例
     */
    private var bleAdvertiserInstance: BleAdvertiser? = null

    /* * * * * * * * * * * * * * * * * * * 变量私有属性 * * * * * * * * * * * * * * * * * * */

    private var deviceBoundStateReceiverRegistered = false

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 内部属性
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 蓝牙适配器
     */
    internal var bluetoothAdapter: BluetoothAdapter? = null

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 内部方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 初始化
     */
    internal fun init(bleInitProvider: BleInitProvider) {
        val context = bleInitProvider.context
        if (context == null) {
            Logger.log(TAG, "init interrupt: context is null")
            return
        }
        InternalConstants.context = context.applicationContext
        bluetoothManager =
            InternalConstants.context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?
        bluetoothAdapter = bluetoothManager?.adapter
        if (bluetoothManager == null) {
            Logger.log(TAG, "get \"android.bluetooth.BluetoothManager\" is null")
        }
        if (bluetoothAdapter == null) {
            Logger.log(TAG, "get \"android.bluetooth.BluetoothAdapter\" is null")
        }
        registerDeviceBoundStateReceiver()
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 公开方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 开启Log打印
     * @param enable true:开启，false:关闭
     */
    fun enableLog(enable: Boolean) {
        Logger.enableLog(enable)
    }

    /**
     * 设置log打印级别
     * @param logLevel 日志级别
     */
    fun setLogLevel(logLevel: LogLevel) {
        Logger.setLogLevel(logLevel)
    }

    /**
     * 判断设备是否LE CODED
     */
    @RequiresApi(Build.VERSION_CODES.O)
    fun isLeCodedPhySupported(): Boolean {
        return bluetoothAdapter?.isLeCodedPhySupported ?: false
    }

    /**
     * 判断设备是否支持蓝牙功能
     */
    fun supportBluetooth(): Boolean {
        return bluetoothManager != null
    }

    /**
     * 判断设备是否支持蓝牙功能
     */
    fun supportBluetoothLe(): Boolean {
        return InternalConstants.context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
    }

    /**
     * 判断蓝牙是否开启
     */
    fun isBlueEnable(): Boolean {
        return bluetoothAdapter?.isEnabled == true
    }

    /**
     * 开启蓝牙
     */
    fun enableBluetooth() {
        val intent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        InternalConstants.context.startActivity(intent)
    }

    /**
     * 关闭蓝牙
     */
    fun closeBluetooth(): Boolean {
        @Suppress("DEPRECATION")
        return bluetoothAdapter?.disable() ?: false
    }

    /**
     * 获取蓝牙适配器
     */
    fun getBluetoothAdapter(): BluetoothAdapter? {
        return bluetoothAdapter
    }

    /**
     * 判断某个BLE设备是否已经连接
     */
    @SuppressLint("MissingPermission")
    fun isGattConnected(device: BluetoothDevice): Boolean {
        return bluetoothManager?.getConnectedDevices(BluetoothProfile.GATT)
            ?.contains(device) == true
    }

    /**
     * 判断某个BLE设备是否已经连接
     */
    fun isGattConnected(address: String): Boolean {
        return isGattConnected(bluetoothAdapter?.getRemoteDevice(address) ?: return false)
    }

    /**
     * 断开某个设备的连接
     */
    fun releaseGattConnection(device: BluetoothDevice) {
        bluetoothManager?.getConnectedDevices(BluetoothProfile.GATT)?.forEach {
            if (it.address == device.address) {
                it.connectGatt(InternalConstants.context, false, null)?.close()
            }
        }
    }

    /**
     * 断开某个设备的连接
     */
    fun releaseGattConnection(address: String) {
        releaseGattConnection(bluetoothAdapter?.getRemoteDevice(address) ?: return)
    }

    /**
     * 获取蓝牙扫描器单例
     * @return 蓝牙扫描器单例
     */
    @Synchronized
    fun getScannerInstance(): BleScanner {
        if (bleScannerInstance == null) {
            bleScannerInstance = BleScanner()
        }
        return bleScannerInstance!!
    }

    /**
     * 释放BLE扫描器单例的内存
     */
    fun releaseBleScannerInstance() {
        bleScannerInstance?.close()
        bleScannerInstance = null
    }

    /**
     * 新建BLE扫描器
     */
    fun newScanner(): BleScanner {
        val bleScanner = BleScanner()
        scannerList.add(bleScanner)
        return bleScanner
    }

    /**
     * 释放BLE扫描器
     */
    fun releaseScanner(bleScanner: BleScanner?) {
        if (bleScanner == null) {
            return
        }
        val index = scannerList.indexOf(bleScanner)
        if (index < 0) {
            return
        }
        val scanner = scannerList.removeAt(index)
        scanner.close()
    }

    /**
     * 释放全部BLE扫描器
     */
    fun releaseAllScanner() {
        scannerList.forEach {
            it.close()
        }
        scannerList.clear()
    }

    /**
     * 获取BLE广播器单例
     */
    @Synchronized
    fun getAdvertiserInstance(): BleAdvertiser {
        if (bleAdvertiserInstance == null) {
            bleAdvertiserInstance = BleAdvertiser()
        }
        return bleAdvertiserInstance!!
    }

    /**
     * 释放BLE广播器单例
     */
    fun releaseAdvertiserInstance() {
        bleAdvertiserInstance?.close()
        bleAdvertiserInstance = null
    }

    /**
     *  获取BLE连接器单例
     */
    @Synchronized
    fun getConnectorInstance(): BleConnector {
        if (bleConnectorInstance == null) {
            bleConnectorInstance = BleConnector()
        }
        return bleConnectorInstance!!
    }

    /**
     * 释放全部与BLE连接器相关的回调与参数
     */
    fun releaseConnectorInstance() {
        closeAllConnectedGatt()
        GlobalConnectVariable.bluetoothGattConnectStateChangedListenerList.clear()
        GlobalConnectVariable.connectTimeOutTimerList.clear()
        GlobalConnectVariable.connectedStateList.clear()
        GlobalConnectVariable.onDescriptorDataOptionListenerList.clear()
        GlobalConnectVariable.onCharacteristicDataOptionsListenerList.clear()
        GlobalConnectVariable.writeLargeDataKeepList.clear()
        GlobalConnectVariable.writeLargeDataContinueFlagList.clear()
        GlobalConnectVariable.onReadRemoteRssiListenerList.clear()
        GlobalConnectVariable.onMtuChangedListenerList.clear()
        GlobalConnectVariable.onPhyOptionsListenerList.clear()
    }

    /**
     *  关闭当前连接过的全部设备的GATT连接
     */
    fun closeAllConnectedGatt() {
        bleConnectorInstance?.closeAllGatt()
    }

    /**
     * 判断某个特征是否有对应的属性
     *  @param characteristic BluetoothGattCharacteristic
     *  @param properties 属性
     *  [BluetoothGattCharacteristic.PROPERTY_READ]
     *  [BluetoothGattCharacteristic.PROPERTY_NOTIFY]
     *  [BluetoothGattCharacteristic.PROPERTY_WRITE]
     *  [BluetoothGattCharacteristic.PROPERTY_BROADCAST]
     *  [BluetoothGattCharacteristic.PROPERTY_INDICATE]
     *  [BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS]
     *  [BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE]
     *  [BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE]
     *  @return 是否有对应的属性
     */
    fun checkCharacteristicProperties(
        characteristic: BluetoothGattCharacteristic, properties: Int
    ): Boolean {
        return characteristic.properties and properties == properties
    }

    /**
     * 判断特征是否可读
     */
    fun characteristicCanRead(characteristic: BluetoothGattCharacteristic): Boolean {
        return checkCharacteristicProperties(
            characteristic, BluetoothGattCharacteristic.PROPERTY_READ
        )
    }

    /**
     * 判断特征是否可写
     */
    fun characteristicCanWrite(characteristic: BluetoothGattCharacteristic): Boolean {
        return checkCharacteristicProperties(
            characteristic, BluetoothGattCharacteristic.PROPERTY_WRITE
        )
    }

    /**
     * 判断特征是否支持通知
     */
    fun characteristicCanNotify(characteristic: BluetoothGattCharacteristic): Boolean {
        return checkCharacteristicProperties(
            characteristic, BluetoothGattCharacteristic.PROPERTY_NOTIFY
        )
    }

    /**
     * 判断某个描述是否有对应的权限
     * @param descriptor BluetoothGattDescriptor
     * @param permissions 要判断的权限
     *
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_READ]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM]
     * [android.bluetooth.BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM]
     *
     * @return 是否有权限
     */
    fun checkDescriptorPermission(
        descriptor: BluetoothGattDescriptor,
        permissions: Int
    ): Boolean {
        val result = descriptor.permissions and permissions == permissions
        return result
    }

    /**
     * 判断描述是否可读
     */
    fun descriptorCanRead(characteristic: BluetoothGattDescriptor): Boolean {
        return checkDescriptorPermission(
            characteristic, BluetoothGattDescriptor.PERMISSION_READ
        )
    }

    /**
     * 判断描述是否可写
     */
    fun descriptorCanWrite(characteristic: BluetoothGattDescriptor): Boolean {
        return checkDescriptorPermission(
            characteristic, BluetoothGattDescriptor.PERMISSION_WRITE
        )
    }

    /**
     * 绑定设备
     */
    fun bindDevice(device: BluetoothDevice): Int {
        if (!hasBluetoothConnectPermission()) {
            return DeviceBoundErrorCode.PERMISSION_BLUETOOTH_CONNECT_NOT_GRANTED
        }
        when (device.bondState) {
            BluetoothDevice.BOND_BONDED -> return DeviceBoundErrorCode.DEVICE_BOND_BONDED
            BluetoothDevice.BOND_BONDING -> return DeviceBoundErrorCode.DEVICE_BOND_BONDING
            else -> {
                Logger.log(
                    TAG,
                    "设备当前未绑定 发起绑定"
                )
            }
        }
        //使用系统API绑定设备
        return if (device.createBond()) {
            DeviceBoundErrorCode.DEVICE_BOND_REQUEST_SUCCESS
        } else {
            DeviceBoundErrorCode.DEVICE_BOND_REQUEST_FAILED
        }
    }

    /**
     * 添加蓝牙状态变化回调监听
     *
     * @param onBluetoothStateChangedListener 蓝牙状态变化回调监听
     */
    @Suppress("MemberVisibilityCanBePrivate")
    fun setOnBluetoothStateChangedListener(onBluetoothStateChangedListener: OnBluetoothStateChangedListener?) {
        GlobalVariable.onBluetoothStateChangedListener = onBluetoothStateChangedListener
    }

    /**
     * 添加设备绑定状态变化回调监听
     */
    fun addDeviceBoundStateChangedListener(
        address: String,
        listener: OnDeviceBondStateChangedListener
    ) {
        GlobalVariable.onDeviceBondStateChangedListeners[address] = listener
    }

    /**
     * 添加设备绑定状态变化回调监听
     */
    fun addDeviceBoundStateChangedListener(
        device: BluetoothDevice,
        listener: OnDeviceBondStateChangedListener
    ) {
        addDeviceBoundStateChangedListener(device.address, listener)
    }

    /**
     * 移除设备绑定状态变化回调监听
     */
    fun removeDeviceBoundStateChangedListener(address: String): OnDeviceBondStateChangedListener? {
        return GlobalVariable.onDeviceBondStateChangedListeners.remove(address)
    }

    /**
     * 移除设备绑定状态变化回调监听
     */
    fun removeDeviceBoundStateChangedListener(device: BluetoothDevice): OnDeviceBondStateChangedListener? {
        return removeDeviceBoundStateChangedListener(device.address)
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 内部方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 将一个整数转换成2个字节的byte数组
     *
     * @param i 整数
     * @return 2个字节的byte数组
     */
    @Size(2)
    internal fun intToByteArrayLength2(i: Int): ByteArray {
        val hexString: String = intToHexStr(i)
        val highByte: Byte
        val lowByte: Byte
        val hexStringMinLength = 2
        if (hexString.length > hexStringMinLength) {
            var substring = hexString.substring(0, hexString.length - 2)
            highByte = substring.toInt(16).toByte()
            substring = hexString.substring(hexString.length - 2)
            lowByte = substring.toInt(16).toByte()
        } else {
            highByte = 0
            lowByte = hexString.toInt(16).toByte()
        }
        return byteArrayOf(highByte, lowByte)
    }

    /**
     * 创建一个定时任务执行器
     */
    internal fun newScheduledExecutorService(corePoolSize: Int): ScheduledExecutorService {
        return ScheduledThreadPoolExecutor(corePoolSize, threadFactory)
    }

    /**
     * 将整数转换成16进制字符串
     *
     * @param i 整数
     * @return 16进制字符串
     */
    internal fun intToHexStr(i: Int): String {
        return Integer.toHexString(i)
    }

    /**
     * byteArray转换成十六进制字符串
     *
     * @param byteArray byte数组
     * @return String 每个Byte值之间空格分隔
     */
    internal fun byteArrayToHexStr(byteArray: ByteArray): String {
        var stmp: String
        val sb = StringBuilder()
        for (aByte in byteArray) {
            stmp = Integer.toHexString(aByte.toInt() and 0xFF)
            sb.append(if ((stmp.length == 1)) "0$stmp" else stmp)
            sb.append(" ")
        }
        return sb.toString().uppercase(Locale.getDefault()).trim()
    }

    /**
     * 将byte数组[2字节]转换成int
     */
    internal fun byteArray2LengthToInt(manufacturerByte: ByteArray): Int {
        return manufacturerByte[0].toInt() and 0xFF shl 8 or (manufacturerByte[1].toInt() and 0xFF)
    }

    /**
     * 将数据反转
     *
     * @param array 原始数据
     */
    internal fun revertData(array: ByteArray) {
        for (i in 0 until array.size / 2) {
            //交换在位置array.length-i和index上的两个数
            val temp = array[array.size - 1 - i]
            array[array.size - 1 - i] = array[i]
            array[i] = temp
        }
    }

    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     *
     * 私有方法
     *
     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

    /**
     * 注册设备绑定状态的广播接收者
     */
    @SuppressLint("UnspecifiedRegisterReceiverFlag")
    @Synchronized
    private fun registerDeviceBoundStateReceiver() {
        if (deviceBoundStateReceiverRegistered) {
            return
        }
        deviceBoundStateReceiverRegistered = true
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            InternalConstants.context.registerReceiver(
                deviceBoundStateReceiver,
                DeviceBoundBroadcastReceiver.getIntentFilter(), Context.RECEIVER_EXPORTED
            )
        } else {
            InternalConstants.context.registerReceiver(
                deviceBoundStateReceiver,
                DeviceBoundBroadcastReceiver.getIntentFilter()
            )
        }
    }
}
